#pragma once
#include <iostream>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>

class Sock
{
public:
    static int sock()
    {
        int ret = socket(AF_INET, SOCK_STREAM, 0);
        if (ret < 0){
            std::cerr << "socket failed" << errno << std::endl;
            exit(1);
        }
        std::cout << "socket success" << std::endl;
        return ret;
    }
    
    //bind 使用的struct sockaddr 需要一直存在，不能随着栈帧销毁
    // static void Bind(int sock, struct sockaddr_in* server){
    //     if (::bind(sock, (struct sockaddr*)server, sizeof(struct sockaddr_in)) < 0){
    //         std::cerr << "bind failed" << errno << std::endl;
    //         exit(2);
    //     }
    //     std::cout << "bind success" << std::endl;
    // }

    static void Bind(int sock, uint16_t port){
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;

        if (bind(sock, (struct sockaddr *)&local, sizeof(local)) <  0)
        {
            std::cerr << "bind error!" << errno <<std::endl;
            exit(3);
        }
        std::cout << "bind success" << std::endl;
    }

    static void Listen(int sock){
        if (::listen(sock, 5) < 0){
            std::cerr << "listen failed" << errno << std::endl;
            exit(3);
        }
        std::cout << "listen success" << std::endl;
    }

    // static int Accept(int sock, struct sockaddr_in* client, socklen_t* len){
    //     int new_sock = ::accept(sock, (struct sockaddr*)client, len);
    //     if (new_sock < 0){
    //         std::cerr << "accept failed" << errno << std::endl;
    //         return -1;
    //     }
    //     std::string cli_addr = inet_ntoa(client->sin_addr);
    //     uint16_t cli_port = ntohs(client->sin_port);
    //     std::cout << "get a accept from [" << cli_addr << ":" << cli_port << "]\n\t" << "new_sock[" << new_sock << "]" << "accept success" << std::endl;
    //     return new_sock;
    // }

    static int Accept(int sock){
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int new_sock = ::accept(sock, (struct sockaddr*)&client, &len);
        if (new_sock < 0){
            std::cerr << "accept failed" << errno << std::endl;
            return -1;
        }
        std::string cli_addr = inet_ntoa(client.sin_addr);
        uint16_t cli_port = ntohs(client.sin_port);
        std::cout << "get a accept from [" << cli_addr << ":" << cli_port << "]\n\t" << "new_sock[" << new_sock << "]" << "accept success" << std::endl;
        return new_sock;
    }

    static void Connect(int sock, struct sockaddr_in* server){
        int ret = ::connect(sock, (struct sockaddr*)server, sizeof(struct sockaddr_in));
        if (ret < 0){
            std::cerr << "connect failed" << errno << std::endl;
            exit(4);
        }
        std::cout << "connect success" << std::endl;
    }
};
